package com.leyou.item.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.type.TypeReference;
import com.leyou.dto.PageDTO;
import com.leyou.exception.LyException;
import com.leyou.item.dto.*;
import com.leyou.item.entity.Sku;
import com.leyou.item.entity.Spu;
import com.leyou.item.entity.SpuDetail;
import com.leyou.item.mapper.SpuMapper;
import com.leyou.item.pojo.Brand;
import com.leyou.item.pojo.Category;
import com.leyou.item.pojo.vo.SpuVo;
import com.leyou.item.service.*;
import com.leyou.utils.JsonUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.amqp.core.AmqpTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author ：qcq
 * @date ：Created in 2020/12/7 11:32
 * @description：
 */
@Service
public class SpuServiceImpl extends ServiceImpl<SpuMapper, Spu> implements SpuService {

    @Autowired
    private BrandService brandService;
    @Autowired
    private CategoryService categoryService;

    @Autowired
    private SkuService skuService;

    @Autowired
    private SpuDetailService spuDetailService;

    @Autowired
    private SpecGroupService specGroupService;

    @Autowired
    private SpecParamService specParamService;

    @Autowired
    private AmqpTemplate amqpTemplate;

    @Override
    public PageDTO<SpuDTO> findPage(Integer page, Integer rows, Boolean saleable, Long brandId, Long categoryId, Long id) {
        QueryWrapper<Spu> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq((brandId != null), "brand_id", brandId)
                .eq((categoryId != null), "cid3", categoryId)
                .eq((id != null), "id", id)
                .eq((saleable != null), "saleable", saleable);
        Page<Spu> spuPage = this.page(new Page<Spu>(page, rows), queryWrapper);
        List<SpuDTO> spuDTOS = SpuDTO.convertEntityList(spuPage.getRecords());
        for (SpuDTO spuDTO : spuDTOS) {
            Brand brand = brandService.getById(spuDTO.getBrandId());
            if (brand != null) {
                String brandName = brand.getName();
                spuDTO.setBrandName(brandName);
            }
            List<Category> categories = categoryService.listByIds(spuDTO.getCategoryIds());
            String categoryName = categories.stream().map(Category::getName).collect(Collectors.joining("/"));
            spuDTO.setCategoryName(categoryName);
        }
        PageDTO<SpuDTO> spuPageDTO = new PageDTO<>(spuPage.getTotal(), spuPage.getPages(), spuDTOS);
        return spuPageDTO;

    }

    @Override
    @Transactional
    public void addGoods(SpuDTO spuDTO) {

        if (CollectionUtils.isEmpty(spuDTO.getSkus())) {
            throw new LyException(400, "每个spu下至少有一个sku");
        }

        //存spu表
        Spu spu = spuDTO.toEntity(Spu.class);
        boolean saveSpu = this.save(spu);
        if (saveSpu) {
            log.debug("spu表添加成功");
        }
        //存sku表
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        for (SkuDTO skuDTO : skuDTOList) {
            skuDTO.setSpuId(spu.getId());
            Sku sku = skuDTO.toEntity(Sku.class);
            boolean saveSku = skuService.save(sku);
            if (saveSku) {
                log.debug("sku表添加成功");
            }
        }
        //存spuDetail表
        SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
        SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
        spuDetail.setSpuId(spu.getId());
        boolean saveSpuDetail = spuDetailService.save(spuDetail);
        if (saveSpuDetail) {
            log.debug("SpuDetail表添加成功");
        }

    }

    @Override
    @Transactional
    public void updateGoods(SpuDTO spuDTO) {
        //改spu表
        Long spuId = spuDTO.getId();
        if(spuId != null){
        Spu spu = spuDTO.toEntity(Spu.class);

            boolean updateSpu = this.updateById(spu);
            if (updateSpu) {
                log.debug("spu表修改成功");
            }
        }

        //改spuDetail表
        if (spuDTO.getSpuDetail() != null) {
            SpuDetailDTO spuDetailDTO = spuDTO.getSpuDetail();
            SpuDetail spuDetail = spuDetailDTO.toEntity(SpuDetail.class);
            boolean updateSpuDetail = spuDetailService.updateById(spuDetail);
            if (updateSpuDetail) {
                log.debug("spuDetail表修改成功");
            }
        }

        //改sku表,sku表可能删除（当saleable==false时删除）、修改（当有spu_id时进行修改）、新增（当没有spu_id时进行新增）
        if (CollectionUtils.isEmpty(spuDTO.getSkus())) {
            return;
        }
        List<SkuDTO> skuDTOList = spuDTO.getSkus();
        Map<Boolean, List<Sku>> map = skuDTOList
                .stream()
                .map(skuDTO -> skuDTO.toEntity(Sku.class))
                .collect(Collectors.groupingBy(sku -> sku.getSaleable() != null));

        List<Sku> updateOrCreateSkus = map.get(true);
        if (!CollectionUtils.isEmpty(updateOrCreateSkus)) {
            skuService.saveOrUpdateBatch(updateOrCreateSkus);
        }
        List<Sku> deleteSkus = map.get(false);
        if (!CollectionUtils.isEmpty(deleteSkus)) {
            List<Long> skuIds = deleteSkus.stream().map(Sku::getId).collect(Collectors.toList());
            skuService.removeByIds(skuIds);
        }

    }

    @Override
    public void goodsOnAndOffShelves(Long id, Boolean saleable) {
        Spu spu = new Spu();
        spu.setId(id);
        spu.setSaleable(saleable);
        spu.setUpdateTime(new Date());
        boolean success = this.updateById(spu);
        if (!success) {
            throw new LyException(500, "更新失败");
        }

        //下架sku
        success = skuService.update().set("saleable", saleable)
                .eq("spu_id", id).update();

        if (!success) {
            throw new LyException(500, "更新失败");
        }

        //发送mq消息
        String routingKey = saleable ? "item.up" : "item.down";
        amqpTemplate.convertAndSend("ly.item.exchange",routingKey,id);
    }

    @Override
    public SpuDTO querySkuAndSpuAndApuDetailById(Long id) {

        Spu spu = this.getById(id);
        SpuDTO spuDTO = new SpuDTO(spu);
        List<Sku> skuList = skuService.query().eq("spu_id", id).list();
        List<SkuDTO> skuDTOList = SkuDTO.convertEntityList(skuList);
        spuDTO.setSkus(skuDTOList);
        SpuDetail spuDetail = spuDetailService.getById(id);
        SpuDetailDTO spuDetailDTO = new SpuDetailDTO(spuDetail);
        spuDTO.setSpuDetail(spuDetailDTO);
        return spuDTO;
    }

    @Override
    public SpuDTO queryGoodsById(Long id) {
        Spu spu = this.getById(id);
        SpuDTO spuDTO = new SpuDTO(spu);
        return spuDTO;
    }

    @Override
    public List<SpecParamDTO> listSpec(Long spuId, Boolean searching) {

        //spuId获取到对应的规格参数，以及规格参数值，规格参数组
        ;

        //查询spu获取分类id
        Long cid = getById(spuId).getCid3();

        //跟分类id查询当前分类下所有的规格参数组


        //普通，遍历规格参数组，根据每个组id查询对应的组内参数

        //跟分类id查询当前分类下所有的规格参数
        List<SpecParamDTO> specParamDTOS = SpecParamDTO
                .convertEntityList(this.specParamService
                        .query()
                        .eq("category_id", cid)
                        .eq(null != searching, "searching", searching)
                        .list());

        //处理每一个specParam的value，？？在spuDetail中


        //对规格参数集合，进行分组，已groupId分组，同id，为一组,key为groupId，value同id一组集合


        //获取规格参数的value，
        SpuDetail spuDetail = this.spuDetailService.getById(spuId);

        //json,class

        //nativeRead 第一个参数，接送，第二个参数，类型限定
        //key 规格参数的id，value，规格参数的值
        Map<Long, Object> valueMap = JsonUtils.nativeRead(spuDetail.getSpecification(), new TypeReference<Map<Long, Object>>() {
        });

        //遍历specParamDTO，给每个value赋值，每个value的值，就是valuemap的value
        specParamDTOS.forEach(specParamDTO -> {

            //规格参数的id
            Long key = specParamDTO.getId();

            specParamDTO.setValue(valueMap.get(key));
        });

        return specParamDTOS;


        /*//spuId获取到对应的规格参数，以及规格参数值，规格参数组;

        //查询spu获取分类id
        Long cid = getById(spuId).getCid3();

        //跟分类id查询当前分类下所有的规格参数组
        List<SpecGroupDTO> specGroupDTOS = SpecGroupDTO
                .convertEntityList(this.specGroupService
                        .query()
                        .eq("category_id", cid)
                        .list());

        //普通，遍历规格参数组，根据每个组id查询对应的组内参数

        //跟分类id查询当前分类下所有的规格参数
        List<SpecParamDTO> specParamDTOS = SpecParamDTO
                .convertEntityList(this.specParamService
                        .query()
                        .eq("category_id", cid)
                        .list());

        //处理每一个specParam的value，？？在spuDetail中


        //对规格参数集合，进行分组，已groupId分组，同id，为一组,key为groupId，value同id一组集合
        Map<Long, List<SpecParamDTO>> specMap =
                specParamDTOS
                        .stream()
                        .collect(Collectors.groupingBy(SpecParamDTO::getGroupId));


        //获取规格参数的value，
        SpuDetail spuDetail = this.spuDetailService.getById(spuId);

        //json,class

        //nativeRead 第一个参数，接送，第二个参数，类型限定
        //key 规格参数的id，value，规格参数的值
        Map<Long, Object> valueMap = JsonUtils.nativeRead(spuDetail.getSpecification(), new TypeReference<Map<Long, Object>>() {
        });

        //遍历specParamDTO，给每个value赋值，每个value的值，就是valuemap的value
        specParamDTOS.forEach(specParamDTO -> {

            //规格参数的id
            Long key = specParamDTO.getId();

            specParamDTO.setValue(valueMap.get(key));
        });

        ;


        specGroupDTOS.forEach(specGroupDTO -> {
            specGroupDTO.setParams(specMap.get(specGroupDTO.getId()));
        });

        //规格参数集合存入到规格参数组中

        return specGroupDTOS;*/
    }
}
